package pers.course.week11.SortCustomers;

import java.util.*;

class Account {
    protected double balance;

    Account(double init_balance) {
        balance = init_balance;
    }

    double getBalance() {
        return balance;
    }

    void deposit(double amt) {
        balance += amt;
    }

    void withdraw(double amt) throws OverdraftException {
        if (amt <= balance) {
            balance -= amt;
        } else throw new OverdraftException("Insufficient funds", amt - balance);
    }
}

class CheckingAccount extends Account {
    double overdraftProtection = 0;

    CheckingAccount(double balance) {
        super(balance);
    }

    CheckingAccount(double balance, double protect) {
        super(balance);
        overdraftProtection = protect;
    }

    void withdraw(double amt) throws OverdraftException {
        if (amt <= balance) {
            balance -= amt;
        } else {
            if (overdraftProtection == 0) {
                throw new OverdraftException("No overdraft protection", amt - balance);
            } else {
                if (amt - balance <= overdraftProtection) {
                    overdraftProtection -= (amt - balance);
                    balance = 0;
                } else throw new OverdraftException("Insufficient funds", amt - balance - overdraftProtection);
            }
        }
    }
}

class SavingsAccount extends Account {
    double interestRate;

    SavingsAccount(double balance, double interest_rate) {
        super(balance);
        interestRate = interest_rate;
    }
}

class Customer implements Comparable<Customer>{
    private String firstName;
    private String lastName;
    private List<Account> account;

    Customer(String f, String l) {
        firstName = f;
        lastName = l;
        account = new ArrayList<>();
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public Account getAccount(int index) {
        return account.get(index);
    }

    public void addAccount(Account acct) {
        account.add(acct);
    }

    public int getNumOfAccounts() {
        return account.size();
    }

    public Iterator<Account> getAccounts() {
        return account.iterator();
    }

    @Override
    public int compareTo(Customer o) {
        if (!this.lastName.equals(o.getLastName())) {
            return this.lastName.compareTo(o.getLastName());
        } else {
            return this.firstName.compareTo(o.getFirstName());
        }
    }
}

class Bank {
    private List<Customer> customers;

    public Bank() {
        customers = new ArrayList<Customer>();
    }

    public void addCustomer(String f, String l) {
        customers.add(new Customer(f, l));
    }

    public Customer getCustomer(int index) {
        return customers.get(index);
    }

    public static Bank instance = new Bank();

    public static Bank getBank() {
        return instance;
    }

    public Iterator<Customer> getCustomers() {
        return customers.iterator();
    }

    public void sortCustomers() {
        customers.sort(Comparator.naturalOrder());
    }
}

class OverdraftException extends Exception {
    private double deficit;

    public OverdraftException(String message, double deficit) {
        super(message);
        this.deficit = deficit;
    }

    public double getDeficit() {
        return deficit;
    }
}

class CustomerReport {
    public void generateReport() {
        Bank bank = Bank.getBank();
        bank.sortCustomers();
        Customer customer;
        Iterator<Customer> iter1 = bank.getCustomers();
        System.out.println("CUSTOMERS REPORT");
        System.out.println("================");
        while (iter1.hasNext()) {
            customer = iter1.next();
            Iterator<Account> iter2 = customer.getAccounts();
            System.out.println();
            System.out.println("Customer: "
                    + "[" + customer.getFirstName() + " " + customer.getLastName() + "]");
            while (iter2.hasNext()) {
                Account account = iter2.next();
                String account_type;
                if (account instanceof CheckingAccount) {
                    account_type = "Checking Account";
                } else {
                    account_type = "Savings Account";
                }
                System.out.println("    " + account_type + ": current balance is "
                        + "$" + account.getBalance());
            }
        }
    }
}

public class SortCustomers {
    public static void main(String[] args) {
        Bank bank = Bank.getBank();
        Customer customer;
        int curCustomer = 0;
        Scanner s = new Scanner(System.in);
        int t = s.nextInt();
        s.nextLine();
        // Create several customers and their accounts according to data
        while (t-- > 0) {
            String f = s.next();
            String l = s.next();
            s.nextLine();
            bank.addCustomer(f, l);
            customer = bank.getCustomer(curCustomer++);
            int numAccount = s.nextInt();
            s.nextLine();
            while (numAccount-- > 0) {
                String[] type = s.nextLine().split(" ");
                double balance;
                double interesOrProtect;
                if (type[0].trim().toUpperCase().equals("C")) {
                    balance = Double.parseDouble(type[1]);
                    if (type.length == 3) {
                        interesOrProtect = Double.parseDouble(type[2]);
                        customer.addAccount(new CheckingAccount(balance,
                                interesOrProtect));
                    } else {
                        customer.addAccount(new CheckingAccount(balance));
                    }
                } else if (type[0].trim().toUpperCase().equals("S")) {
                    balance = Double.parseDouble(type[1]);
                    interesOrProtect = Double.parseDouble(type[2]);
                    customer.addAccount(new SavingsAccount(balance,
                            interesOrProtect));
                }
            }
        }
        int nOPs = s.nextInt();
        s.nextLine();
        while (nOPs-- > 0) {
            String[] sOP = s.nextLine().split(" ");
            char op = sOP[0].charAt(0);
            int customerIndex = Integer.parseInt(sOP[1]);
            int accountIndex = Integer.parseInt(sOP[2]);
            double amount = Double.parseDouble(sOP[3]);
            switch (op) {
                case 'w':
                case 'W':
                    customer = bank.getCustomer(customerIndex);
                    try {
                        customer.getAccount(accountIndex).withdraw(amount);
                    } catch (OverdraftException ode) {
                        System.out.print("[" + customer.getFirstName() + " " + customer.getLastName() + "]");
                        System.out.println(" withdraw " + amount + ", " + ode.getMessage() + ": " + ode.getDeficit());
                    }
                    break;
                case 'd':
                case 'D':
                    customer = bank.getCustomer(customerIndex);
                    customer.getAccount(accountIndex).deposit(amount);
                    break;
            }
        }
        // Generate a report
        CustomerReport cr = new CustomerReport();
        cr.generateReport();
    }
}